package com.asen.commons.core.meta.helper;

import com.asen.commons.exception.JdbcException;
import com.asen.commons.core.meta.entity.EntityField;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.*;

/**
 * 实体属性辅助类
 *
 * @author ls
 * @version 1.0
 * @date 2024-04-10
 */
public class EntityFieldHelper {

    /**
     * 获取所有实体属性
     *
     * @param entityClass
     * @return
     */
    public static List<EntityField> getAllFields(Class<?> entityClass) {
        List<EntityField> fieldList = new ArrayList<EntityField>();
        _getFields(entityClass, fieldList, _getGenericTypeMap(entityClass), null);
        return fieldList;
    }

    public static EntityField getField(Class<?> clazz, String fieldName) {
        List<EntityField> fieldList = getAllFields(clazz);
        for (EntityField field : fieldList) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }
        return null;
    }

    private static void _getFields(Class<?> entityClass, List<EntityField> fieldList, Map<String, Class<?>> genericMap, Integer level) {
        if (fieldList == null) {
            throw new NullPointerException("fieldList参数不能为空!");
        }

        if (level == null) {
            level = 0;
        }

        if (entityClass == Object.class) {
            return;
        }

        Field[] fields = entityClass.getDeclaredFields();
        int index = 0;
        for (Field field : fields) {

            // 覆盖父类中相同名称的属性
            boolean fieldExist = false;
            for (EntityField eField : fieldList) {
                if (eField.getName().equals(field.getName())) {
                    fieldExist = true;
                    break;
                }
            }

            if (fieldExist) {
                continue;
            }

            EntityField entityField = null;
            if (field.getGenericType() != null && field.getGenericType() instanceof TypeVariable) {
                if (genericMap == null || !genericMap.containsKey(((TypeVariable) field.getGenericType()).getName())) {
                    TypeVariable typeVariable = (TypeVariable) field.getGenericType();
                    Type[] bounds = typeVariable.getBounds();
                    if (bounds == null || bounds.length == 0) {
                        throw new JdbcException(entityClass + "字段" + field.getName() + "的泛型类型无法获取!");
                    }
                    Type bound = bounds[0];
                    entityField = new EntityField(field);
                    entityField.setJavaType(bound.getClass());
                } else {
                    entityField = new EntityField(field);
                    entityField.setJavaType(genericMap.get(((TypeVariable) field.getGenericType()).getName()));
                }
            } else {
                entityField = new EntityField(field);
            }

            if (level.intValue() != 0) {
                //将父类的字段放在前面
                fieldList.add(index, entityField);
                index++;
            } else {
                fieldList.add(entityField);
            }
        }

        //获取父类和泛型信息
        Class<?> superClass = entityClass.getSuperclass();
        if (superClass == null) {
            return;
        }

        // 父类如果是集合类型就不查了
        if (Map.class.isAssignableFrom(superClass)
                || Collection.class.isAssignableFrom(superClass)) {
            return;
        }

        level++;
        _getFields(superClass, fieldList, genericMap, level);
    }

    /**
     * 获取所有泛型类型映射
     *
     * @param entityClass
     */
    private static Map<String, Class<?>> _getGenericTypeMap(Class<?> entityClass) {
        Map<String, Class<?>> genericMap = new HashMap<String, Class<?>>();
        if (entityClass == Object.class) {
            return genericMap;
        }

        //获取父类和泛型信息
        Class<?> superClass = entityClass.getSuperclass();
        if (superClass == null || superClass.equals(Object.class)) {
            return genericMap;
        }

        if (Map.class.isAssignableFrom(superClass)
                || Collection.class.isAssignableFrom(superClass)) {
            return genericMap;
        }

        if (entityClass.getGenericSuperclass() instanceof ParameterizedType) {
            Type[] types = ((ParameterizedType) entityClass.getGenericSuperclass()).getActualTypeArguments();
            TypeVariable[] typeVariables = superClass.getTypeParameters();
            if (typeVariables.length > 0) {
                for (int i = 0; i < typeVariables.length; i++) {
                    if (types[i] instanceof Class) {
                        genericMap.put(typeVariables[i].getName(), (Class<?>) types[i]);
                    }
                }
            }
        }

        genericMap.putAll(_getGenericTypeMap(superClass));

        return genericMap;
    }

}
